home *** CD-ROM | disk | FTP | other *** search
- /*
- * cy Copyright © 1995 by Rick Younie
- * Freely Distributable.
- * Do not distribute your changes please.
- *
- * $VER: Rick Younie 10 March 1995
- * rick@freenet.vancouver.bc.ca (quicker)
- * rick@emma.panam.wimsey.com (may be more reliable)
- *
- * USAGE: '?' for usage
- *
- * SYNOPSIS:
- * - Cybercron management program
- *
- */
- signal on BREAK_C
- signal on HALT
-
- /* -------------------------------------------------------------------
- * constants and assigns
- */
- /* set these for your system */
-
- screenwidth = 640
- screenheight = 200
- editor = 'C:ed -sticky' /* editor must hang on to CLI */
- CyberCron = 'CyberCron' /* path+name of CC program */
- crontab = 'SYS:s/CronTab'
- sendmail = '"sendmail -f %s -R *"%s*""'
- logfile = 't:CyberCron.log'
-
- /* end settings */
-
-
- lf = '0a'x
- cr = '0d'x
- crlf = cr || lf
- csi = '9b'x
- rows = screenheight % 8 - 2
- cols = screenwidth % 8 - 1
- startcmd = CyberCron 'CRONTAB' crontab,
- 'SENDMAIL' sendmail
-
- /* -------------------------------------------------------------------
- *
- */
- Main:
- address 'CYBERCRON'
- options results
- options failat 99
- arg option
-
- select
- when option = '-N' then call NextEvent
- when option = '-L' then call ListEvents
-
- when option = '-E' then call Edit
-
- when option = '-B' then call StartCyber
- when option = '-Q' | option = '-K' then call KillCyber
-
- when option = '-S'
- then if Suspend_Resume('SUSPEND') then say ShowStatus()
- when option = '-R'
- then if Suspend_Resume('RESUME') then say ShowStatus()
-
- when option = '' then call RawStuff
-
- otherwise Call Usage
- end
- exit 0
-
- /*####################################################################
- ## raw window ##
- ####################################################################*/
-
- /* -----------------------------------------------------------------*/
-
- RawStuff:
-
- cursorUp = '41'x
- cursorDown = '42'x
- cursorRight = '43'x
- cursorLeft = '44'x
-
- if ~Running()
- then call ErX "..CyberCron not running - '?' for Usage"
-
- call MakeRaw
-
- Refresh:
- call WriteSkel /* write header,footer */
-
- ReScan:
- numevents = ReadEvents() /* get all queued events from CC */
-
- if numevents = 0 then page = 0
- else page = 1
- row = 1
-
- itemsPerPage = rows - 8
- itemsLastPage = numevents // itemsPerPage
- maxpage = numevents % itemsPerPage + (itemsLastPage~=0)
-
- items. = itemsPerPage
- items.0 = 1
- if itemsLastPage = 0 then items.maxpage = itemsPerPage
- else items.maxpage = itemsLastPage
-
- if numevents~=0 then call WritePage
- else call WriteSkel
-
- /* we spend most of our time here, handling keystrokes
- *
- */
- do forever
-
- oldpos = row
- char = readch('STDIN', 1)
-
- select
-
- /* handle cursor keys */
- when char = '9b'x then do
- char = readch('STDIN', 1)
- select
- when numevents=0 then nop
- when char = cursorDown then do
- row = row + 1
- if row > items.page then row = 1
- call MoveCursor
- end
- when char = cursorUp then do
- row = row - 1
- if row = 0 then row = items.page
- call MoveCursor
- end
- when char = cursorRight then do
- if page ~= maxpage then do
- page = page + 1
- call WritePage
- end
- end
- when char = cursorLeft then do
- if page > 1 then do
- page = page - 1
- call WritePage
- end
- end
- otherwise nop
- end
-
- end /* cursor keys */
-
- /* not a cursor key */
- otherwise do
- select
- when char = 's'
- then if Suspend_Resume('SUSPEND') then call WriteStatus
- when char = 'r'
- then if Suspend_Resume('RESUME') then call WriteStatus
- when char = 'a' then call AddEvent('NORM')
- when char = 'A' then call AddEvent('CC')
- when char = 'e' then call EditCrontab
- when char = 'n' then signal Refresh /* ReScan? */
- when char = 'q' then do
- call CLineMsg '..really quit? Y/n '
- char = readch('STDIN',1)
- if upper(char)~='N' then leave
- call MsgAndDelay '..quit aborted'
- end
- when char = 'g' then call ToggleLogFile
-
- /* dont allow the following options if no events */
- when numevents = 0 then nop
-
- when char = 't' then do
- tmp = (page-1)*itemsPerPage + row
- tag.tmp = (tag.tmp=0) /* toggle flag */
- if tag.tmp then star = '*'
- else star = ' '
- call writech 'STDOUT',csi || row+2';3H'star
- row = row + 1
- if row > items.page then row = 1
- call MoveCursor
- end
-
- /* space bar follows Tin behavior
- * >1 page?
- * - if ~last page, go to next
- * - else if not at end of page, go to end
- * - else go to first page
- * =1 page; if not at bottom, go there
- * else go to top
- */
- when char = ' ' then do
- if maxpage > 1 then do
- if page ~= maxpage then do
- page = page + 1
- call WritePage
- end
- else do
- if row ~= items.page then do
- row = items.page
- call MoveCursor
- end
- else do
- page = 1
- call WritePage
- end
- end
- end
- else do /* only 1 page; go to bot/top */
- if row = items.page then row = 1
- else row = items.page
- call MoveCursor
- end
- end
-
- when char = 'd' then call DeleteEvent
- when char = 'p' then call PurgeRexx
- otherwise nop
- end
- end
-
- end /* select */
-
- call PrintTime
-
- end /* forever */
-
- exit 0
-
- MoveCursor:
- call writech 'STDOUT', csi || oldpos+2';1H '
- call writech 'STDOUT', csi || row+2';1H->' || csi || rows';1H'
- return
-
- CLineMsg:
- call writech 'STDOUT', csi || rows';1H'csi'K 'arg(1) || cr
- return
-
- /* -------------------------------------------------------------------
- *
- */
- WriteSkel:
- prompt.1 = '[s]uspend [r]esume [t]ag [d]elete [e]dit_crontab resca[n] lo[g]_file'
- prompt.2 = '<=prev page (spacebar) next page=> [aA]dd [q]uit [p]urge_rexx_events'
-
- 'VERSION'
- title = 'CyberCron' word(result,1)
-
- call writech 'STDOUT', csi'H'csi'J' || center(title,cols) || crlf
- call writech 'STDOUT', csi || rows - 4';1H'center(prompt.1,cols)
- call writech 'STDOUT', csi || rows - 3';1H'center(prompt.2,cols)
-
- WriteStatus:
- call writech 'STDOUT', csi || rows - 2';1H'center(ShowStatus(),cols)
- call CLineMsg ''
-
- PrintTime:
- call writech 'STDOUT', csi || '1;4H'time()' 'date('E') || csi || rows';1H'
- return
-
- /* ------------------------------------------------------------------- */
- WritePage:
-
- tmp = right('p'page 'of' maxpage,10)
- call writech 'STDOUT', csi || '1;'cols-length(tmp)'H'tmp
-
- offset = (page-1)*itemsPerPage /* offset into event.i */
-
- /* write this pages events to window */
- do i = 1 to items.page
- tmp = offset + i
- if tag.tmp then star = '*'
- else star = ' '
- call writech 'STDOUT', csi || i+2';1H'csi'K 'star || event.tmp || crlf
- end i
-
- /* clear leftover lines */
- do i = items.page+1 to itemsPerPage + 1
- call writech 'STDOUT', csi || i+2';1H'csi'K'
- end i
-
- /* reset to first entry whenever page is redrawn */
- row = 1
- call writech 'STDOUT', csi || row+2';1H->'
-
- WipeBottom2:
- /* wipe 2 command lines, positions cursor at bottom */
- call writech 'STDOUT', csi || rows-1';1H'csi'J'csi || rows';1H'
- return
-
- /* ----------------------------------------------------------------
- * ssc_id.i = 12345678'ext' 12345678 0x12345678 for the sort
- * - ext=ext+1 for every CC event read so :OBEYQUEUE-type
- * events dont get mixed up by the sort
- * - shifted to just 'ssc id' after the sort
- * event.i = time date event_to_execute
- */
- ReadEvents:
-
- tag. = 0 /* clear tags on a new read */
-
- /* get all events in CC-id format */
- 'LIST_EVENTS'
- list = result
-
- if left(list,2)~='0x' then ssc_id.0 = 0 /* no events queued */
-
- else do
- if option = '' then call CLineMsg '..getting events'
- /* fill 'sssc.ext sssc 0x' array for sort */
- ssc_id.0 = words(list)
- do i = 1 to ssc_id.0
- /* get time for its next execution */
- id = word(list,i)
- 'EVENT_NEXT_EXEC' id
- ssc = result
- if ssc = '' then tmp = 0 /* could not be found */
- tmp = ssc || right('0'i,2) /* 01,02..added to events
- so QUEUE events of same time dont scramble */
- ssc_id.i = tmp ssc id
- end i
-
- if option = '' then call CLineMsg '..sorting'
-
- /* one of Knuth's sort algorithms
- - rony@wu-wien.ac.at (Rony G. Flatscher) */
- m = 1
- do while (9 * m + 4) < ssc_id.0
- m = m * 3 + 1
- end
-
- do while m > 0
- k = ssc_id.0 - M
- do j = 1 to k
- q = j
- do while q > 0
- l = q + m
- if ssc_id.q <= ssc_id.l then leave
- /* switch elements */
- tmp = ssc_id.q
- ssc_id.q = ssc_id.l
- ssc_id.l = tmp
- q = q - m
- end
- end
- m = m % 3
- end /* sort */
-
- if option = '' then call CLineMsg '..converting'
-
- /* now fill event.i with events sorted as to time */
- today = date('E')
- scnwidth = cols - 4
- do i = 1 to ssc_id.0
-
- parse var ssc_id.i . ssc id
- /* lose the ssc+extension variable to save a little confusion */
- ssc_id.i = ssc id
-
- 'SHOW_EVENT' id
- event.i = subword(result,7) /* the event */
-
- 'EXPAND_SSSC' ssc
- parse var result . min hr day mon yr .
- date = right('00'day,2)'/'right('00'mon,2)'/'right(yr,2)
- if date = today then date = ' '
-
- /* truncate for screen */
- event.i = right('00'hr,2)':'right('00'min,2) date event.i
- if length(event.i) > scnwidth then event.i = left(event.i,scnwidth)
- end i
-
- end
-
- return ssc_id.0
-
- /* -------------------------------------------------------------------
- *
- */
- PurgeRexx:
- 'PURGE_REXX_EVENTS' /* no RC? */
- call MsgAndDelay '..rexx events purged'
- signal ReScan
-
- /* -------------------------------------------------------------------
- *
- */
- ToggleLogFile:
-
- if right(ShowStatus(),2) = 'ON' then 'CLOSE_LOG_FILE'
- else 'NEW_LOG_FILE' logfile
-
- if RC ~= 0 then call MsgAndDelay '..error toggling' logfile
-
- signal WriteStatus
-
- return
-
- /* -------------------------------------------------------------------
- *
- */
- EditCrontab:
- call CLineMsg '..editing' crontab
- if Edit()~=0 then do
- call delay 3*50
- signal Refresh /* dos can mess up window with err msg */
- end
- signal ReScan
-
- Edit:
- address 'COMMAND' editor crontab
- return RC
-
- /* -------------------------------------------------------------------
- * NORM = hh:mm event
- * CC = min hour day month dow(Sun=0) event
- */
- AddEvent:
- parse arg type
-
- prompt.NORM = 'hh:mm'
- prompt.CC = 'min hr day mon dow(Sun=0)'
- prompt = csi || rows-1';1H'csi'K'prompt.type' event'csi || rows';1H'
-
- do forever
- call writech 'STDOUT',prompt
- string = GetEvent()
- if string = '' then do
- call MsgAndDelay '..aborting - no add'
- signal WipeBottom2
- end
- if type = 'NORM' then do
- parse var string hr ':' min event
- event = strip(event)
- string = min hr '* * *' event
- end
-
- 'ADD_EVENT' string
-
- /* event was added ok - go get new lineup from CC */
- if RC=0 then do
- call MsgAndDelay 'ok'
- signal ReScan
- end
-
- else do /* not added - try again */
- call writech 'STDOUT', csi || rows-1';33H **error** [ <ret> to continue ]'
- call readch 'STDIN', 1
- call writech 'STDOUT', csi || rows-1';1H'csi'J'csi || rows
- end
-
- end
- return
-
- /* ----------------handle user add_event input---------------------- */
- GetEvent:
- string = ''
-
- do forever
- char = readch('STDIN',1)
- select
- when char>'1f'x & char < '7f'x then do
- if length(string) <= cols-2 then string = string || char
- else char = '07'x
- call writech 'STDOUT',char
- end
-
- /* delete a character */
- when char = '08'x then do
- if string ~== '' then do
- string = substr(string,1,length(string)-1)
- call writech 'STDOUT', csi'D'csi'P'
- end
- end
-
- /* done */
- when char = cr then break
-
- /* discard cursor key 2nd byte */
- when char = csi then call readch 'STDIN',1
- otherwise nop
- end
- end
- return string
-
- /* -------------------------------------------------------------------
- * Delete all tagged events; else current event
- */
- DeleteEvent:
-
- /* any tagged for delete? */
- tagged = 0
- do i = 1 to numevents
- tagged = tagged + tag.i
- end i
-
- /* got tagged event(s) */
- if tagged > 0 then do
- call CLineMsg 'delete' tagged 'tagged event'copies('s',tagged~=1)'? Y/n '
- char = readch('STDIN',1)
- if upper(char)='N' then break
- do i = 1 to numevents
- if tag.i then call DeleteOne word(ssc_id.i,2)
- end
- signal ReScan
- end
-
- /* delete current event? */
- call CLineMsg 'delete this event? Y/n '
- char = readch('STDIN',1)
- if upper(char)='N' then call MsgAndDelay '..aborting - no delete'
- else do
- tmp = (page-1)*itemsPerPage+row
- call DeleteOne word(ssc_id.tmp,2)
- signal ReScan
- end
- return
-
- DeleteOne:
- parse arg id
- call CLineMsg '..deleting'
- 'DELETE_EVENT' id
- if RC~=0 then call MsgAndDelay '..couldn''t find event'
- return
-
- /* ------ write a message to command line, wait, then wipe it ----- */
- MsgAndDelay:
- parse arg msg
- call CLineMsg msg
- call delay 25
- call CLineMsg ''
- return
-
- /*####################################################################
- ## do command line requests ##
- ####################################################################*/
-
- /* -----------------------------------------------------------------*/
- ListEvents:
- if ~Running() then say '..CyberCron isn''t running'
- else do
- 'LIST_EVENTS'
- list = result
- if left(list,2)~='0x' then say '..no events queued'
- else do i = 1 to words(list)
- 'SHOW_EVENT' word(list,i)
- say subword(result,2)
- end
- say ' 'ShowStatus()
- end
- return
-
- /* -----------------------------------------------------------------*/
- NextEvent:
- if ~Running() then say '..CyberCron isn''t running'
- else do
- numevents = ReadEvents()
- if numevents = 0 then say '..no events queued'
- else do
- lasttime = word(ssc_id.1,1) /* show all events queued for next time */
- do i = 1 to numevents
- thistime = word(ssc_id.i,1)
- if thistime ~= lasttime then break
- id = word(ssc_id.i,2)
- say event.i
- lasttime = thistime
- end i
- say ' 'ShowStatus()
- end
- end
- return
-
- /* ------------------------------------------------------------- */
- Suspend_Resume:
- running = Running()
- if ~running then say '..CyberCron isn''t running'
- else ''arg(1)''
- return running
-
- /* ------------------------------------------------------------- */
- ShowStatus: PROCEDURE
- 'SHOW_STATUS'
- parse var result activity ' "' ctab '" "' lfile '"'
- star = copies('*',activity='SUSPENDED')
- if lfile = '<None>' then tmp = 'OFF'
- else tmp = 'ON'
- return 'Status:'star||activity||star 'Crontab='ctab 'Log='tmp
-
- /* ------------------------------------------------------------- */
- KillCyber:
- if ~Running() then say '..CyberCron isn''t running'
- else do
- 'QUIT'
- do i = 1 to 10
- call delay 25
- if ~Running() then break
- end i
-
- if i <= 10 then say '..CyberCron is dead'
- else say '..CyberCron will quit after the current job is finished'
- end
- return
-
- /* ------------------------------------------------------------- */
- StartCyber:
- if Running() then say '..CyberCron is already running'
- else do
- address 'COMMAND' 'run >NIL: <NIL:' startcmd
-
- do i = 1 to 10
- call delay 25
- if Running() then break
- end i
-
- if i <= 10 then say '..CyberCron started'
- else say '..couldn''t start' CyberCron
- end
- return
-
- /* ------ 0=not running; 1=running ------------------------------ */
- Running:
- return show('PORT','CYBERCRON')
-
- /* ---------------------------------------------------------------- */
- MakeRaw:
- call close 'STDOUT'
- call close 'STDIN'
- call open 'STDOUT','RAW:0/0/'screenwidth'/'screenheight'//NOSIZE'
- call pragma '*','STDOUT'
- call open 'STDIN','*'
- return
-
- /* ---------------------------------------------------------------- */
- Usage:
- say 'Usage: cy -option'
- say ' -e edit crontab ['editor crontab']'
- say ' -b begin CyberCron ['CyberCron']'
- say ' -q quit (kill) CyberCron'
- say ' -s suspend'
- say ' -r resume'
- say ' -n next event(s) to execute'
- say ' -l list all events'
- say ' no option is the most fun'
- say ' editor =' editor
- say ' logfile =' logfile
- say ' crontab =' crontab
- exit 0
-
- ErX:
- say arg(1)
-
- HALT:
- BREAK_C:
- exit 10
-